package com.qys.livesMall.shop.service.api.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.qys.livesMall.common.exception.QysException;
import com.qys.livesMall.common.result.R;
import com.qys.livesMall.common.utils.MessageUtils;
import com.qys.livesMall.framework.utils.SecurityUtils;
import com.qys.livesMall.framework.utils.SnowflakeGenerator;
import com.qys.livesMall.shop.constants.OrderStatus;
import com.qys.livesMall.shop.constants.PayStatus;
import com.qys.livesMall.shop.constants.ShopConstant;
import com.qys.livesMall.shop.modal.dto.shop.order.AddOrder;
import com.qys.livesMall.shop.modal.dto.shop.order.DirectAddOrder;
import com.qys.livesMall.shop.modal.dto.shop.order.NavyAddOrder;
import com.qys.livesMall.shop.modal.dto.shop.order.SeckillAddOrder;
import com.qys.livesMall.shop.modal.entity.*;
import com.qys.livesMall.shop.open.anchor.service.AnchorServer;
import com.qys.livesMall.shop.scheduledTask.DelayTaskDispatcher;
import com.qys.livesMall.shop.scheduledTask.taksEnum.TaskTypeEnum;
import com.qys.livesMall.shop.scheduledTask.task.OrderTaks;
import com.qys.livesMall.shop.service.*;
import jakarta.annotation.Resource;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @packageName:
 * @className:ShopOrderServiceImpl
 * @Description:
 * @author:guomx
 * @date:2023/7/2011:44
 */
@Service
public class ShopOrderServiceImpl implements ShopOrderService{
    @Resource
    private ShopOrderInfoService orderInfoService;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private SeckillGoodsService seckillGoodsService;

    @Resource
    private SeckillOrderService seckillOrderService;
    @Resource
    private SeckillActivityService activityService;

    @Resource
    private ShopCartService cartService;
    @Resource
    private AnchorServer anchorServer;

    public ShopOrderServiceImpl() {
    }

    @Override
    public ShopOrder add(AddOrder addOrder) {
        ShopOrderInfo order = new ShopOrderInfo();
        order.setId(Long.valueOf(getOrderId()));
        BeanUtils.copyProperties(addOrder,order);

        List<ShopCart> cartList = cartService.list(addOrder.getCartIds());
        if(cartList.size()==0){
            return null;
        }
        List<ShopOrderSku> skus = new ArrayList<>();
        cartList.stream().forEach(cart->{
            ShopOrderSku orderSku=JSON.parseObject(JSON.toJSONString(cart), ShopOrderSku.class);
            if (cart.getTaskId()!=null) {
                orderSku.setAnchorId(anchorServer.getAnchorIdByTaskId(cart.getTaskId()));
            }
            skus.add(orderSku);
        });


        R<ShopOrder> res = orderInfoService.add(order,skus, ShopConstant.OrderSource.CART);
        if (res.getSuccess()){
            cartService.delete(addOrder.getCartIds());

            OrderTaks orderTaks = new OrderTaks();
            orderTaks.setOrderId(order.getId().toString());
            orderTaks.setTaskType(TaskTypeEnum.Order.getTaskType());
            orderTaks.setTimeout(30);
            orderTaks.setTimeUnit(TimeUnit.MINUTES);
            DelayTaskDispatcher.offerTask(orderTaks);
        }
        return res.getData();
    }

    private String getOrderId(){
        long snowID = SnowflakeGenerator.generateSnowflakeID(1L);
        String afterId = String.valueOf(snowID);
        String id = "2" + afterId;
        return id;
    }

    @Override
    public ShopOrder add(DirectAddOrder addOrder) {
        ShopOrderInfo order = new ShopOrderInfo();
        order.setId(Long.valueOf(getOrderId()));
        BeanUtil.copyProperties(addOrder,order);

        ShopOrderSku orderSku=new ShopOrderSku();
        BeanUtil.copyProperties(addOrder,orderSku);
        Integer source=ShopConstant.OrderSource.DIRECT;
        if (orderSku.getTaskId()!=null) {
            orderSku.setAnchorId(anchorServer.getAnchorIdByTaskId(orderSku.getTaskId()));
            source=ShopConstant.OrderSource.LIVE_ROOM;

        }
        List<ShopOrderSku> orderSkus=new ArrayList();
        orderSkus.add(orderSku);

        R<ShopOrder> res =orderInfoService.add(order,orderSkus, source);
        if (res.getSuccess()){
            OrderTaks orderTaks = new OrderTaks();
            orderTaks.setOrderId(order.getId().toString());
            orderTaks.setTaskType(TaskTypeEnum.Order.getTaskType());
            orderTaks.setTimeout(30);
            orderTaks.setTimeUnit(TimeUnit.MINUTES);
            DelayTaskDispatcher.offerTask(orderTaks);
        }
      return res.getData();
    }

    @Override
    public R<ShopOrder> add(SeckillAddOrder addOrder) {
        RLock lock = redissonClient.getLock("seckillOrder_" + SecurityUtils.getUserId());
        try {
            boolean locked = lock.tryLock(5, TimeUnit.SECONDS);
            if (locked) {
                ShopOrderInfo order = new ShopOrderInfo();
                order.setId(Long.valueOf(getOrderId()));
                BeanUtil.copyProperties(addOrder,order);
                long now = System.currentTimeMillis();
                Long skId = addOrder.getSeckillGoodsId();
                SeckillGoods seckillGoods = seckillGoodsService.getById(skId);
                SeckillActivity activity = activityService.getById(seckillGoods.getActivityId());
                long startTime = activity.getStartTime();
                long endTime = activity.getEndTime();
                if (now<startTime){
                    return R.fail(MessageUtils.message("seckill.not.started"));
                }
                if (now>endTime){
                    return R.fail(MessageUtils.message("seckill.is.end"));
                }
                Integer num = addOrder.getNum();
                if (num.equals(0)){
                    return R.fail(MessageUtils.message("seckil.num.null"));
                }
                String seckillNum = seckillGoods.getNum();
                if (!seckillNum.equals("0")){
                    if (Integer.valueOf(seckillNum) <num){
                        return R.fail(MessageUtils.message("seckil.num.null"));
                    }
                    LambdaQueryWrapper<SeckillOrder> seckillOrderLambdaQueryWrapper = new LambdaQueryWrapper<>();
                    seckillOrderLambdaQueryWrapper.eq(SeckillOrder::getUserId, SecurityUtils.getUserId());
                    seckillOrderLambdaQueryWrapper.eq(SeckillOrder::getSeckillGoodsId,seckillGoods.getId());
                    seckillOrderLambdaQueryWrapper.ne(SeckillOrder::getStatus,PayStatus.PAYMENT_FAILURE);
                    List<SeckillOrder> seckillOrderList = seckillOrderService.list(seckillOrderLambdaQueryWrapper);
                    if (ObjectUtils.isNotEmpty(seckillOrderList)){
                        int sumNum = seckillOrderList.stream().mapToInt(seckillOrder -> Integer.valueOf(seckillOrder.getNum())).sum();
                        if (sumNum+num>Integer.valueOf(seckillNum)){
                            return R.fail(MessageUtils.message("seckil.num.null"));
                        }
                    }
                }
                BigDecimal price = seckillGoods.getSeckillPrice();
                ShopOrderSku orderSku=new ShopOrderSku();
                BeanUtil.copyProperties(addOrder,orderSku);
                orderSku.setPrice(price);
                orderSku.setMoney(price.multiply(new BigDecimal(addOrder.getNum())));
                List<ShopOrderSku> orderSkus=new ArrayList();
                orderSkus.add(orderSku);
                //下单
                SeckillOrder seckillOrder = new SeckillOrder();
                seckillOrder.setSeckillActivityId(seckillGoods.getActivityId());
                seckillOrder.setSeckillGoodsId(seckillGoods.getId().toString());
                seckillOrder.setNum(orderSku.getNum());
                seckillOrder.setMoney(orderSku.getMoney());
                seckillOrder.setUserId(order.getUserId().toString());
                seckillOrder.setUsername(order.getUserName());
                seckillOrder.setCreateTime(System.currentTimeMillis());
                seckillOrder.setStatus(PayStatus.NONPAYMENT);
                seckillOrder.setId(order.getId());
                seckillOrderService.save(seckillOrder);
                order.setSeckillOrderId(order.getId());

                R<ShopOrder> res =orderInfoService.add(order,orderSkus, ShopConstant.OrderSource.SECKILL);
                if (res.getSuccess()){

                    OrderTaks orderTaks = new OrderTaks();
                    orderTaks.setOrderId(order.getId().toString());
                    orderTaks.setTaskType(TaskTypeEnum.Order.getTaskType());
                    orderTaks.setTimeout(15);
                    orderTaks.setTimeUnit(TimeUnit.MINUTES);
                    DelayTaskDispatcher.offerTask(orderTaks);
                }
                return res;
            } else {
                return R.fail(MessageUtils.message("payment.failed"));
            }

        }catch (QysException e){
            return R.fail(e.getMessage());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }finally {
            lock.unlock();
        }
    }

    @Override
    public R pay(Long orderId) {

        // 使用分布式锁确保只有一个线程能够执行支付操作
        RLock lock = redissonClient.getLock("pay_" + orderId);
        try {
            boolean locked = lock.tryLock(5, TimeUnit.SECONDS);
            if (locked) {
                // 检查订单是否已支付，如果已支付则返回失败
                if (isOrderPaid(orderId)) {
                    return R.fail(MessageUtils.message("order.has.been.paid"));
                }
                orderInfoService.pay(orderId);
                // 执行支付操作
                return R.ok();
            } else {
                return R.fail(MessageUtils.message("payment.failed"));
            }
        }catch (QysException e){
            return R.fail(e.getCode(),e.getMessage());
        }
        catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return R.fail(MessageUtils.message("payment.failed"));
        } finally {
            lock.unlock();
        }
    }

    private boolean isOrderPaid(Long orderNumber) {
        // 检查订单是否已支付的逻辑
        // 可以查询订单状态或检查支付记录等
        // 返回 true 表示订单已支付，返回 false 表示订单未支付
        ShopOrderInfo orderInfo = orderInfoService.getById(orderNumber);
        if (Objects.equals(orderInfo.getPayStatus(), PayStatus.HAVE_PAYMENT)){
            return true;
        }
        return false;
    }
}
